home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / progjrn / pj_6_4.arc / RESIDENT.ASM < prev    next >
Assembly Source File  |  1987-08-30  |  11KB  |  399 lines

  1. ; This code illustrates how to install and deinstall a TSR and under what
  2. ; circumstances the body of a TSR should be given control.
  3. ;
  4. ; The hot keys in this example are the Alt + Left Shift keys.  This hot key
  5. ; combination is defined in the variable hot_keys and can be changed to suit
  6. ; the user by changing the bit pattern.
  7. ;
  8. ; This example is intended to illustrate the recommendations made in the
  9. ; following articles:
  10. ;
  11. ;    "DOS: Terminate and Stay Resident", M. Steven Baker
  12. ;    Programmer's Journal, Nov/Dec 1986, pages 26 - 30
  13. ;
  14. ;    "Coding Guidelines for Resident Programs", Graham Pearson
  15. ;    Programmer's Journal, Mar/Apr 1987, pages 34 - 38
  16. ;
  17. ;
  18. ; The author can be reached at the following address:
  19. ;    Kudos Software,  9111 Cadawac Road,  Houston, Texas 77074
  20. ;    Tel: (713) 774-6108
  21.  
  22. ;******************************************************************************
  23.  
  24. DELAY_COUNT    EQU    36        ;Timer counts between hot key triggers
  25.                     ;36 ticks = approx. 2 seconds
  26.  
  27. ; Locations of BIOS Data needed by the resident program
  28.  
  29. bios_data    segment at 40H
  30.     org        17H        ;Keyboard status flags
  31.     kbd_status    dw    ?
  32.     org        6CH        ;Timer count - low word. This rolls
  33.     low_timer    dw    ?    ;around 0FFFFH once per hour
  34. bios_data    ends
  35.  
  36. ;------------------------------------------------------------------------------
  37.  
  38. code        segment
  39.     assume    cs:code, ds:nothing, es:nothing, ss:nothing
  40.     org    100H            ;Define starting point for .COM file
  41.  
  42. entry_point:
  43.     jmp    install         ;Skip over the code to be made resident
  44.  
  45. ;------------------------------------------------------------------------------
  46.  
  47.     hot_keys    dw    01010B    ;Hot key bits -> Alt + Left Shift
  48.  
  49.     this_time    dw    ?    ;Most-recent time hot keys detected
  50.     trig_time    dw    ?    ;Last time resident code was triggered
  51.  
  52.     dos_busy    label    dword    ;Pointer to "DOS is busy" flag
  53.     dos_busy_off    dw    ?    ;These values are initialized during
  54.     dos_busy_seg    dw    ?    ;the "install" process
  55.  
  56.     criterr_flag    dw    ?    ;Used by diverted INT 24H
  57.  
  58. ;------------------------------------------------------------------------------
  59.  
  60. ; Replacement for INT 24H - critical DOS error
  61.  
  62. diverted_int24:
  63.  
  64.     mov    cs:criterr_flag,0FFFFH    ;Switch error flag ON
  65.     xor    al,al            ;Tell DOS to ignore the error
  66.     iret                ;Return to DOS
  67.  
  68.     int_24_vect    label    dword
  69.     int_24_off    dw    ?    ;These values are initialized each time
  70.     int_24_seg    dw    ?    ;the TSR body takes control
  71.  
  72. ;------------------------------------------------------------------------------
  73.  
  74. ; Replacement for INT 9 - keyboard hardware interrupt
  75.  
  76. diverted_int9:
  77.  
  78.     pushf                ;Simulate an INT 9 to pass through the
  79.     call_int9    db    09AH    ;original BIOS interrupt handler
  80.     int_9_vect    label    dword
  81.     int_9_off    dw    ?    ;These values are initialized during
  82.     int_9_seg    dw    ?    ;the "install" process
  83.  
  84.     push    ds            ;Save all registers used by this
  85.     push    bx            ;section of code
  86.     lds    bx,dos_busy        ;See if DOS is busy
  87.     cmp    byte ptr [bx],0
  88.     pop    bx            ;Restore all registers
  89.     pop    ds
  90.     jz    get_bios_data        ;Zero means DOS is not busy
  91.  
  92. dos_is_busy:
  93.     iret                ;Return control to interrupted process
  94.  
  95. ;------------------------------------------------------------------------------
  96.  
  97. ; Replacement for INT 28 - generated by DOS, esp. during keyboard I/O functions
  98.  
  99. diverted_int28:
  100.  
  101.     pushf                ;Simulate an INT 28H to pass through
  102.     call_int28    db    09AH    ;the original DOS interrupt handler
  103.     int_28_vect    label    dword
  104.     int_28_off    dw    ?    ;These values are initialized during
  105.     int_28_seg    dw    ?    ;the "install" process
  106.  
  107. ;------------------------------------------------------------------------------
  108.  
  109. get_bios_data:
  110.  
  111.     sti                ;Restore interrupts
  112.     push    ds            ;Save all registers used by this
  113.     push    bx            ;section of code
  114.  
  115.     mov    bx,bios_data        ;Retrieve BIOS Data values
  116.     mov    ds,bx
  117.     assume    ds:bios_data
  118.  
  119.     mov    bx,low_timer        ;Retrieve and save timer count
  120.     mov    cs:this_time,bx
  121.     mov    bx,kbd_status        ;Retrieve keyboard status bits
  122.  
  123.     push    cs            ;Point DS to our code segment
  124.     pop    ds
  125.     assume    ds:code
  126.  
  127. chk_keys:
  128.     and    bx,hot_keys        ;See if hot keys are pressed
  129.     cmp    bx,hot_keys
  130.     jne    back_to_applic
  131.  
  132. chk_timer:
  133.     mov    bx,this_time
  134.     cmp    bx,trig_time        ;Enter resident routine if timer
  135.     jb    time_is_right        ;count has rolled around the hour
  136.  
  137.     sub    bx,trig_time
  138.     sub    bx,DELAY_COUNT        ;Transfer to resident code only if
  139.     jnc    time_is_right        ;elapsed time between hot keys is
  140.                     ;greater than delay count
  141. back_to_applic:
  142.     pop    bx            ;Restore all registers
  143.     pop    ds
  144.     iret                ;Return control to interrupted process
  145.  
  146. ;------------------------------------------------------------------------------
  147.  
  148. time_is_right:
  149.     mov    bx,this_time        ;Update latest trigger time
  150.     mov    trig_time,bx
  151.     pop    bx            ;Restore all registers
  152.     pop    ds
  153.  
  154. ;******************************************************************************
  155.  
  156. ; This is the start of the application-dependent resident code
  157.  
  158. start_program:
  159.  
  160.     push    ax            ;Save all registers used by the
  161.     push    bx            ;resident application
  162.     push    cx
  163.     push    dx
  164.     push    si
  165.     push    di
  166.     push    bp
  167.     push    ds
  168.     push    es
  169.  
  170.     push    cs            ;Point DS to our CS
  171.     pop    ds
  172.  
  173.     mov    ax,3524H        ;Get current INT 24H vector
  174.     int    21H
  175.     mov    int_24_off,bx
  176.     mov    int_24_seg,es
  177.     mov    ax,2524H        ;Redirect INT 24H
  178.     mov    dx,offset diverted_int24
  179.     int    21H
  180.  
  181.  
  182. ;******************************************************************************
  183.  
  184.     ; Include application specific code here
  185.  
  186. ;******************************************************************************
  187.  
  188.  
  189. restore_int24:
  190.     lds    dx,int_24_vect        ;Restore INT 24H
  191.     mov    ax,2524H        ;Error in PJ listing (was 2509H)
  192.     int    21H
  193.  
  194.     pop    es            ;Restore all registers
  195.     pop    ds
  196.     pop    bp
  197.     pop    di
  198.     pop    si
  199.     pop    dx
  200.     pop    cx
  201.     pop    bx
  202.     pop    ax
  203.     iret                ;Return control to interrupted process
  204.  
  205. ; This is the end of the application-dependent resident code
  206.  
  207.     end_of_res    label    word
  208.  
  209. ;******************************************************************************
  210.  
  211. ; This procedure installs the resident section of code in memory.
  212. ; It performs the following tasks:
  213. ;
  214. ;    1    Make sure the operating system is at least DOS 2.00
  215. ;
  216. ;    2    Make sure the resident code is not already installed in memory
  217. ;    If it IS already installed, remove it from memory
  218. ;
  219. ;    3    Retrieve an available vector for installing the signature
  220. ;
  221. ;    4    Retrieve vector to "DOS is busy" and save it for use by resident code
  222. ;
  223. ;    5    Update the interrupt vectors required by resident code.
  224. ;
  225. ;    6    Install the signature in the available vector found in step 3
  226. ;
  227. ;    7    Terminate and stay resident - transfer control back to DOS
  228.  
  229. ;------------------------------------------------------------------------------
  230.  
  231. install:
  232.  
  233. ; Make sure that the operating system is at least DOS 2.00
  234.  
  235.     mov    ah,30H
  236.     int    21H
  237.     or    al,al
  238.     jnz    chk_vectors
  239.  
  240.     mov    dx,offset baddos_msg    ;DS:DX -> Display "bad DOS" message
  241.     mov    ah,9
  242.     int    21H
  243.  
  244.     int    20H            ;Return to DOS the old-fashioned way
  245.  
  246. ;------------------------------------------------------------------------------
  247.  
  248. ; See if the resident code is already installed in memory.
  249. ; If so, remove the resident code from memory.
  250. ; If not, retain an available interrupt vector for later use as a signature.
  251.  
  252. chk_vectors:
  253.     push    ds            ;Save DS -> CS
  254.  
  255.     xor    ax,ax            ;Search 32 interrupt vectors starting
  256.     mov    ds,ax            ;at INT 60H - user interrupt area
  257.     mov    si,60H * 4
  258.     mov    cx,20H
  259.  
  260. next_vector:
  261.     mov    ax,[si + 2]
  262.     or    ax,ax            ;If segment value is zero, get offset
  263.     jz    get_vect_off        ;value
  264.  
  265.     cmp    ax,0D0C7H        ;Check interrupt segment value against
  266.     jne    vector_loop        ;resident code signature
  267.  
  268. deinstall:
  269.     mov    bx,[si]         ;Retrieve original resident code
  270.                     ;segment value
  271.     xor    ax,ax
  272.     mov    [si],ax         ;Remove signature from the
  273.     mov    [si + 2],ax        ;interrupt vector
  274.  
  275. restore_int9:
  276.     mov    ds,bx            ;DS -> original resident code segment
  277.     lds    dx,int_9_vect        ;Restore INT 9 - keyboard I/O
  278.     mov    ax,2509H
  279.     int    21H
  280.  
  281. restore_int28:
  282.     mov    ds,bx            ;DS -> original resident code segment
  283.     lds    dx,int_28_vect        ;Restore INT 28 - DOS interrupt
  284.     mov    ax,2528H
  285.     int    21H
  286.  
  287.     mov    es,bx            ;ES -> code segment to be deinstalled
  288.     mov    ah,49H
  289.     int    21H            ;Free allocated memory
  290.  
  291.     mov    es,es:[2CH]        ;ES -> environment to be deinstalled
  292.     mov    ah,49H
  293.     int    21H            ;Free allocated memory
  294.  
  295.     pop    ds            ;Restore DS -> CS
  296.     mov    dx,offset remove_msg    ;DS:DX -> Display "remove" message
  297.     mov    ah,9
  298.     int    21H
  299.  
  300.     mov    ax,4C01H        ;Return error code of 1
  301.     int    21H            ;Return to DOS with error code
  302.  
  303. get_vect_off:
  304.     cmp    word ptr [si],0     ;If offset value is zero, this vector
  305.     je    found_vector        ;is available for our use
  306.  
  307. vector_loop:
  308.     add    si,4            ;Interrogate next vector
  309.     loop    next_vector
  310.  
  311. found_vector:
  312.  
  313.     ;Make sure we successfully complete the install process before
  314.     ;installing the signature in this available interrupt vector
  315.  
  316.     pop    ds            ;Restore Data Segment
  317.     mov    free_vector,si        ;Save free vector for later
  318.  
  319. ;------------------------------------------------------------------------------
  320.  
  321. ; Retrieve original interrupt vectors and install these in the resident code.
  322. ; Redirect the interrupt vectors to point to resident code.
  323. ; Install signature in available interrupt vector.
  324.  
  325.     push    es            ;Save ES -> CS
  326.  
  327.     mov    ah,34H            ;Retrieve segment + offset
  328.     int    21H            ;pointer to "DOS is busy" flag
  329.     mov    dos_busy_off,bx
  330.     mov    dos_busy_seg,es
  331.  
  332.     mov    ax,3509H        ;Get current INT 9H vector
  333.     int    21H
  334.     mov    int_9_off,bx
  335.     mov    int_9_seg,es
  336.     mov    ax,2509H        ;Redirect INT 9H
  337.     mov    dx,offset diverted_int9
  338.     int    21H
  339.  
  340.     mov    ax,3528H        ;Get current INT 28H vector
  341.     int    21H
  342.     mov    int_28_off,bx
  343.     mov    int_28_seg,es
  344.     mov    ax,2528H        ;Redirect INT 28H
  345.     mov    dx,offset diverted_int28
  346.     int    21H
  347.  
  348.     pop    es            ;Restore ES -> CS
  349.     mov    di,free_vector        ;Retrieve value found earlier
  350.  
  351.     push    ds            ;Save DS -> CS
  352.     xor    ax,ax            ;DS -> interrupt vectors
  353.     mov    ds,ax
  354.     mov    [di],cs         ;Install signature in the available
  355.     mov    word ptr [di+2],0D0C7H    ;interrupt vector
  356.     pop    ds            ;Restore DS -> CS
  357.  
  358. ;------------------------------------------------------------------------------
  359.  
  360. ; Display installed message
  361.  
  362.     mov    dx,offset success_msg    ;DS:DX -> Display "success" message
  363.     mov    ah,9
  364.     int    21H
  365.  
  366. ;------------------------------------------------------------------------------
  367.  
  368. ; Prepare for program "terminate and stay resident"
  369.  
  370.     mov    dx,offset end_of_res    ;Calculate the amount of memory used
  371.     dec    dx            ;by the resident code
  372.     or    dx,0FH
  373.     inc    dx            ;Round up to the nearest paragraph
  374.  
  375.     mov    cl,4            ;Convert code size to paragraphs
  376.     shr    dx,cl
  377.     mov    ax,03100H        ;Return error code of 0
  378.     int    21H            ;Terminate but stay resident
  379.  
  380. ;------------------------------------------------------------------------------
  381.  
  382.     free_vector    dw    ?    ;Pointer to available interrupt vector
  383.  
  384.     copyright    db    '  Copyright (c) 1986 Kudos Software  '
  385.  
  386.     baddos_msg    db    'TSR will not run with DOS 1.XX'
  387.             db    0DH, 0AH, '$'
  388.  
  389.     remove_msg    db    'TSR is no longer resident in memory'
  390.             db    0DH, 0AH,'$'
  391.  
  392.     success_msg    db    'TSR successfully installed in memory'
  393.             db    0DH, 0AH, '$'
  394.  
  395. ;------------------------------------------------------------------------------
  396.  
  397. code        ends
  398.         end    entry_point    ;Define entry point for .COM file
  399.